{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# City street network orientations\n",
    "\n",
    "Author: [Geoff Boeing](https://geoffboeing.com/)\n",
    "\n",
    "Compare the spatial orientations of city street networks with OSMnx.\n",
    "\n",
    "  - [Documentation](https://osmnx.readthedocs.io/)\n",
    "  - [Journal article and citation info](https://doi.org/10.1111/gean.70009)\n",
    "  - [Code repository](https://github.com/gboeing/osmnx)\n",
    "  - [Examples gallery](https://github.com/gboeing/osmnx-examples)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#!uv pip install --system --quiet osmnx[all]\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import osmnx as ox\n",
    "\n",
    "weight_by_length = False\n",
    "\n",
    "ox.__version__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# define the study sites as label : query\n",
    "places = {\n",
    "    # 'Atlanta'       : 'Atlanta, Georgia, USA',\n",
    "    # 'Boston'        : 'Boston, MA, USA',\n",
    "    \"Buffalo\": \"Buffalo, NY, USA\",\n",
    "    # 'Charlotte'     : 'Charlotte, NC, USA',\n",
    "    # 'Chicago'       : 'Chicago, IL, USA',\n",
    "    \"Cleveland\": \"Cleveland, OH, USA\",\n",
    "    # 'Dallas'        : 'Dallas, TX, USA',\n",
    "    # 'Houston'       : 'Houston, TX, USA',\n",
    "    # 'Denver'        : 'Denver, CO, USA',\n",
    "    # 'Detroit'       : 'Detroit, MI, USA',\n",
    "    # 'Las Vegas'     : 'Las Vegas, NV, USA',\n",
    "    # 'Los Angeles'   : {'city':'Los Angeles', 'state':'CA', 'country':'USA'},\n",
    "    # 'Manhattan'     : 'Manhattan, NYC, NY, USA',\n",
    "    \"Miami\": \"Miami, FL, USA\",\n",
    "    \"Minneapolis\": \"Minneapolis, MN, USA\",\n",
    "    # 'Orlando'       : 'Orlando, FL, USA',\n",
    "    # 'Philadelphia'  : 'Philadelphia, PA, USA',\n",
    "    # 'Phoenix'       : 'Phoenix, AZ, USA',\n",
    "    # 'Portland'      : 'Portland, OR, USA',\n",
    "    # 'Sacramento'    : 'Sacramento, CA, USA',\n",
    "    \"San Francisco\": {\"city\": \"San Francisco\", \"state\": \"CA\", \"country\": \"USA\"},\n",
    "    # 'Seattle'       : 'Seattle, WA, USA',\n",
    "    # 'St Louis'      : 'St. Louis, MO, USA',\n",
    "    # 'Tampa'         : 'Tampa, FL, USA',\n",
    "    \"Washington\": \"District of Columbia, USA\",\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# verify OSMnx geocodes each query to what you expect (i.e., a [multi]polygon geometry)\n",
    "gdf = ox.geocoder.geocode_to_gdf(list(places.values()))\n",
    "gdf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# create figure and axes\n",
    "n = len(places)\n",
    "ncols = int(np.ceil(np.sqrt(n)))\n",
    "nrows = int(np.ceil(n / ncols))\n",
    "figsize = (ncols * 5, nrows * 5)\n",
    "fig, axes = plt.subplots(nrows, ncols, figsize=figsize, subplot_kw={\"projection\": \"polar\"})\n",
    "\n",
    "# plot each city's polar histogram\n",
    "for ax, place in zip(axes.flat, sorted(places.keys())):\n",
    "    print(ox.utils.ts(), place)\n",
    "\n",
    "    # get undirected graphs with edge bearing attributes\n",
    "    G = ox.graph.graph_from_place(place, network_type=\"drive\")\n",
    "    Gu = ox.bearing.add_edge_bearings(ox.convert.to_undirected(G))\n",
    "    fig, ax = ox.plot.plot_orientation(Gu, ax=ax, title=place, area=True)\n",
    "\n",
    "# add figure title and save image\n",
    "suptitle_font = {\n",
    "    \"family\": \"DejaVu Sans\",\n",
    "    \"fontsize\": 60,\n",
    "    \"fontweight\": \"normal\",\n",
    "    \"y\": 1,\n",
    "}\n",
    "fig.suptitle(\"City Street Network Orientation\", **suptitle_font)\n",
    "fig.tight_layout()\n",
    "fig.subplots_adjust(hspace=0.35)\n",
    "fig.savefig(\"images/street-orientations.png\", facecolor=\"w\", dpi=100, bbox_inches=\"tight\")\n",
    "plt.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also calculate the orientation entropy of a spatial graph with the `ox.bearing.orientation_entropy` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
